#include <iostream>
using namespace std;
#include <string>
#include <cstring>
#include <cerrno>
#include <cstdio>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
// 这四个头文件是写套接字经常用到的
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// version 3 多线程版

void Usage(char *proc)
{
    cout << "Usage: " << proc << " port " << endl;
}

void ServerRoutine(int socket)
{
    while (true)
    {
        char buffer[1024] = {0};
        ssize_t s = read(socket, buffer, sizeof(buffer) - 1);
        if (s > 0)
        {
            // s-1位置是回车，用0 覆盖做结尾
            buffer[s - 1] = 0;
            cout << "client :>" << buffer << endl;
            // 服务器返回信息
            write(socket, buffer, strlen(buffer));
        }
        else if (s == 0)
        {
            cout << "client quit......" << endl;
            break;
        }
        else
        {
            cerr << "read error" << endl;
        }
    }
}

// 线程执行函数
void *PthreadRequest(void *args)
{
    // 先脱离
    pthread_detach(pthread_self());
    int sock = *(int *)args;
    delete (int *)args;
    ServerRoutine(sock);
    // 服务完成，关闭描述符
    close(sock);
}

int main(int argc, char *argv[])
{
    // 服务前准备
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    // 1.创建套接字
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock < 0)
    {
        cerr << "socket error:" << errno << endl;
        return 2;
    }

    // 2.bind端口号
    uint16_t srv_port = atoi(argv[1]);
    struct sockaddr_in server;
    bzero(&server, sizeof(server)); // 将结构体所有数据置0
    server.sin_family = AF_INET;
    server.sin_port = htons(srv_port);
    server.sin_addr.s_addr = INADDR_ANY;
    if (bind(listen_sock, (struct sockaddr *)&server, sizeof(server)) < 0)
    {
        cerr << "bind error :" << errno << endl;
        return 3;
    }
    // 3.开始listen
    const int back_log = 5;
    if (listen(listen_sock, back_log) < 0)
    {
        cerr << "listen error " << endl;
        return 4;
    }
    // 4.accept链接
    for (;;)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int new_sock = accept(listen_sock, (sockaddr *)&peer, &len);
        if (new_sock < 0)
        {
            continue;
        }
        // 提供服务
        cout << "new client link success :" << new_sock << endl;
        int *pram = new int(new_sock);
        pthread_t tid;
        pthread_create(&tid, nullptr, PthreadRequest, (void *)pram);
    }
    return 0;
}